home *** CD-ROM | disk | FTP | other *** search
/ Amiga Tools 2 / Amiga Tools 2.iso / tools / jade / src / amiga_menus.c < prev    next >
C/C++ Source or Header  |  1995-03-09  |  8KB  |  373 lines

  1. /* amiga_menus.c -- Pull-down menu handling for AmigaDOS
  2.    Copyright (C) 1993, 1994 John Harper <jsh@ukc.ac.uk>
  3.  
  4.    This file is part of Jade.
  5.  
  6.    Jade is free software; you can redistribute it and/or modify it
  7.    under the terms of the GNU General Public License as published by
  8.    the Free Software Foundation; either version 2, or (at your option)
  9.    any later version.
  10.  
  11.    Jade is distributed in the hope that it will be useful, but
  12.    WITHOUT ANY WARRANTY; without even the implied warranty of
  13.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.    GNU General Public License for more details.
  15.  
  16.    You should have received a copy of the GNU General Public License
  17.    along with Jade; see the file COPYING.  If not, write to
  18.    the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  19.  
  20. #include "jade.h"
  21. #include "jade_protos.h"
  22.  
  23. #define INTUI_V36_NAMES_ONLY
  24. #include <clib/intuition_protos.h>
  25. #include <clib/gadtools_protos.h>
  26. #include <string.h>
  27. #include <ctype.h>
  28.  
  29. #ifdef NEED_MEMORY_H
  30. # include <memory.h>
  31. #endif
  32.  
  33. #define MAX_MENUS 500
  34. #define NMSIZE (MAX_MENUS * sizeof(struct NewMenu))
  35.  
  36. _PR void ami_clear_menu(struct Window *);
  37. _PR void ami_set_menu(struct Window *);
  38. _PR VALUE evalmenu(WORD, WORD);
  39.  
  40. _PR void ami_mark_menus(void);
  41. _PR void ami_menus_init(void);
  42. _PR void ami_menus_kill(void);
  43.  
  44. static struct Menu *menu_strip;
  45. static struct NewMenu *new_menu;
  46. static APTR vis_info;
  47.  
  48. #ifdef AMIGA_NEED_VARARGS_STUBS
  49. struct Menu *
  50. CreateMenus(struct NewMenu *newMenu, Tag firstTag, ...)
  51. {
  52.     return(CreateMenusA(newMenu, (struct TagItem *)&firstTag));
  53. }
  54. APTR
  55. GetVisualInfo(struct Screen *screen, Tag firstTag, ...)
  56. {
  57.     return(GetVisualInfoA(screen, (struct TagItem *)&firstTag));
  58. }
  59. BOOL
  60. LayoutMenus(struct Menu *menu, APTR vi, Tag firstTag, ...)
  61. {
  62.     return(LayoutMenusA(menu, vi, (struct TagItem *)&firstTag));
  63. }
  64. #endif /* AMIGA_NEEDS_VARARGS_STUBS */
  65.  
  66. void
  67. ami_clear_menu(struct Window *wd)
  68. {
  69.     ClearMenuStrip(wd);
  70.     wd->Flags |= WFLG_RMBTRAP;
  71. }
  72.  
  73. static void
  74. clear_all_menus(void)
  75. {
  76.     VW *thisvw;
  77.     for(thisvw = view_chain; thisvw; thisvw = thisvw->vw_Next)
  78.     {
  79.     if(thisvw->vw_Window)
  80.         ami_clear_menu(thisvw->vw_Window);
  81.     }
  82. }
  83.  
  84. void
  85. ami_set_menu(struct Window *wd)
  86. {
  87.     if(menu_strip)
  88.     {
  89.     SetMenuStrip(wd, menu_strip);
  90.     wd->Flags &= ~WFLG_RMBTRAP;
  91.     }
  92. }
  93.  
  94. static void
  95. set_all_menus(void)
  96. {
  97.     VW *thisvw;
  98.     for(thisvw = view_chain; thisvw; thisvw = thisvw->vw_Next)
  99.     {
  100.     if(thisvw->vw_Window)
  101.         ami_set_menu(thisvw->vw_Window);
  102.     }
  103. }
  104.  
  105. _PR VALUE cmd_set_menu_enabled(VALUE stat, VALUE vw);
  106. DEFUN("set-menu-enabled", cmd_set_menu_enabled, subr_set_menu_enabled, (VALUE stat, VALUE vw), V_Subr2, DOC_set_menu_enabled) /*
  107. ::doc:set_menu_enabled::
  108. set-menu-enabled ENABLED-P [WINDOW]
  109. <AMIGA-ONLY>
  110.  
  111. If ENABLED-P is non-nil the menu will be active in WINDOW, if WINDOW is not
  112. specified, menus will be enabled in *all* windows. When a menu is not enabled
  113. in a window right mouse button events will be detectable.
  114.  
  115. Note that for a menu to be displayed the `set-menu' command must be used first
  116. to create a menu strip.
  117. ::end:: */
  118. {
  119.     if(NILP(vw))
  120.     {
  121.     if(!NILP(stat))
  122.         set_all_menus();
  123.     else
  124.         clear_all_menus();
  125.     }
  126.     else
  127.     {
  128.     if(!NILP(stat))
  129.         ami_set_menu(VWIN(vw)->vw_Window);
  130.     else
  131.         ami_clear_menu(VWIN(vw)->vw_Window);
  132.     }
  133.     return(sym_t);
  134. }
  135.  
  136. _PR VALUE cmd_menu_enabled_p(VALUE vw);
  137. DEFUN("menu-enabled-p", cmd_menu_enabled_p, subr_menu_enabled_p, (VALUE vw), V_Subr1, DOC_menu_enabled_p) /*
  138. ::doc:menu_enabled_p::
  139. menu-enabled-p [WINDOW]
  140. <AMIGA-ONLY>
  141.  
  142. Returns t if a menu is being displayed in WINDOW (or the current window).
  143. ::end:: */
  144. {
  145.     if(!WINDOWP(vw))
  146.     vw = curr_vw;
  147.     return(VWIN(vw)->vw_Window->MenuStrip ? sym_t : sym_nil);
  148. }
  149.  
  150. _PR VALUE cmd_set_menu(VALUE args);
  151. DEFUN("set-menu", cmd_set_menu, subr_set_menu, (VALUE args), V_SubrN, DOC_set_menu) /*
  152. ::doc:set_menu::
  153. set-menu MENUS...
  154. <AMIGA-ONLY>
  155.  
  156. Creates a new menustrip, each window then has these menus.
  157. Each MENU defines a single menu block, it has this format,
  158.  
  159.     (MENU-NAME MENU-ITEM...)
  160.  
  161. MENU-NAME is the name of the block, each MENU-ITEM defines a single menuitem,
  162. they are either nil (empty menu item) or look like,
  163.  
  164.     (ITEM-NAME [SHORTCUT] COMMAND)
  165.  
  166. ITEM-NAME is the item name, SHORTCUT is an optional keyboard shortcut (a one
  167. character long string) and COMMAND is the command to be called when the
  168. menu is selected (see the function `call-command').
  169.  
  170. The shortcuts may be upper or lower case. Menu shortcuts are only
  171. considered to be case-significant when two shortcuts of the same letter (but
  172. different case) are defined.
  173. ::end:: */
  174. {
  175.     if(!CONSP(args))
  176.     {
  177.     signal_arg_error(args, 0);
  178.     return(NULL);
  179.     }
  180.     struct NewMenu *nm = mycalloc(NMSIZE);
  181.     if(nm)
  182.     {
  183.     struct NewMenu *cur = nm;
  184.     ami_menus_kill();
  185.     while(CONSP(args) && CONSP(VCAR(args)))
  186.     {
  187.         VALUE menu = VCAR(args);
  188.         cur->nm_Type = NM_TITLE;
  189.         cur->nm_Label = VSTR(STRINGP(VCAR(menu)) ? VCAR(menu) : null_string);
  190.         cur++;
  191.         menu = VCDR(menu);
  192.         while(CONSP(menu))
  193.         {
  194.         VALUE item = VCAR(menu);
  195.         cur->nm_Type = NM_ITEM;
  196.         if(CONSP(item) && STRINGP(VCAR(item)))
  197.         {
  198.             cur->nm_Label = VSTR(VCAR(item));
  199.             item = VCDR(item);
  200.             if(CONSP(item) && STRINGP(VCAR(item)))
  201.             {
  202.             cur->nm_CommKey = VSTR(VCAR(item));
  203.             item = VCDR(item);
  204.             }
  205.             if(CONSP(item))
  206.             cur->nm_UserData = VCAR(item);
  207.         }
  208.         else
  209.             cur->nm_Label = NM_BARLABEL;
  210.         cur++;
  211.         menu = VCDR(menu);
  212.         }
  213.         args = VCDR(args);
  214.     }
  215.     cur->nm_Type = NM_END;
  216.     cur++;
  217.     new_menu = mymalloc((cur - nm) * sizeof(struct NewMenu));
  218.     if(new_menu)
  219.     {
  220.         memcpy(new_menu, nm, (cur - nm) * sizeof(struct NewMenu));
  221.         myfree(nm);
  222.     }
  223.     else
  224.         new_menu = nm;
  225.  
  226.     menu_strip = CreateMenus(new_menu, TAG_END);
  227.     if(menu_strip)
  228.     {
  229.         vis_info = GetVisualInfo(curr_vw->vw_Window->WScreen, TAG_END);
  230.         if(vis_info)
  231.         {
  232.         if(LayoutMenus(menu_strip, vis_info,
  233. #if AMIGA_INCLUDE_VER >= 39
  234.                    GTMN_NewLookMenus, TRUE,
  235. #endif
  236.                    TAG_END))
  237.         {
  238.             set_all_menus();
  239.             return(sym_t);
  240.         }
  241.         else
  242.             cmd_signal(sym_error, LIST_1(MKSTR("Can't layout menus")));
  243.         FreeVisualInfo(vis_info);
  244.         vis_info = NULL;
  245.         }
  246.         else
  247.         cmd_signal(sym_error, LIST_1(MKSTR("Can't get visual info")));
  248.         FreeMenus(menu_strip);
  249.         menu_strip = NULL;
  250.     }
  251.     else
  252.         cmd_signal(sym_error, LIST_1(MKSTR("Can't create menus")));
  253.     myfree(new_menu);
  254.     new_menu = NULL;
  255.     }
  256.     return(NULL);
  257. }
  258.  
  259. /*
  260.  * This routine is used so we can make command key shortcuts case
  261.  * sensitive - is there an easier way than this???
  262.  */
  263. static struct MenuItem *
  264. findcommmenu(u_char commKey)
  265. {
  266.     struct Menu *menu;
  267.     for(menu = menu_strip; menu; menu = menu->NextMenu)
  268.     {
  269.     struct MenuItem *mi;
  270.     for(mi = menu->FirstItem; mi; mi = mi->NextItem)
  271.     {
  272.         struct MenuItem *si;
  273.         for(si = mi->SubItem; si; si = si->NextItem)
  274.         {
  275.         if(si->Command == commKey)
  276.             return(si);
  277.         }
  278.         if(mi->Command == commKey)
  279.         return(mi);
  280.     }
  281.     }
  282.     return(FALSE);
  283. }
  284.  
  285. /*
  286.  * called from IDCMP event loop
  287.  */
  288. VALUE
  289. evalmenu(WORD code, WORD qual)
  290. {
  291.     VALUE res = sym_nil;
  292.     if(menu_strip)
  293.     {
  294.     struct MenuItem *mi;
  295.     while(mi = ItemAddress(menu_strip, code))
  296.     {
  297.         VALUE command;
  298.         if(mi->Command && (qual & IEQUALIFIER_RCOMMAND))
  299.         {
  300.         struct MenuItem *actual;
  301.         if(qual & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT))
  302.         {
  303.             if(actual = findcommmenu(toupper(mi->Command)))
  304.             mi = actual;
  305.         }
  306.         else
  307.         {
  308.             if(actual = findcommmenu(tolower(mi->Command)))
  309.             mi = actual;
  310.         }
  311.         code = MENUNULL;
  312.         }
  313.         else
  314.         code = mi->NextSelect;
  315.         command = GTMENUITEM_USERDATA(mi);
  316.         if(command)
  317.         res = cmd_call_command(command, sym_nil);
  318.         refresh_world();
  319.         cursor(curr_vw, CURS_ON);
  320.     }
  321.     }
  322.     return(res);
  323. }
  324.  
  325. void
  326. ami_mark_menus(void)
  327. {
  328.     if(new_menu)
  329.     {
  330.     struct NewMenu *nm = new_menu;
  331.     while(nm->nm_Type != NM_END)
  332.     {
  333.         if(nm->nm_Label != NM_BARLABEL)
  334.         {
  335.         MARKVAL(VAL(STRING_HDR(nm->nm_Label)));
  336.         if(nm->nm_CommKey)
  337.             MARKVAL(VAL(STRING_HDR(nm->nm_CommKey)));
  338.         MARKVAL(VAL(nm->nm_UserData));
  339.         }
  340.         nm++;
  341.     }
  342.     }
  343. }
  344.  
  345. void
  346. ami_menus_init(void)
  347. {
  348.     ADD_SUBR(subr_set_menu_enabled);
  349.     ADD_SUBR(subr_menu_enabled_p);
  350.     ADD_SUBR(subr_set_menu);
  351. }
  352.  
  353. void
  354. ami_menus_kill(void)
  355. {
  356.     if(menu_strip)
  357.     {
  358.     clear_all_menus();
  359.     FreeMenus(menu_strip);
  360.     menu_strip = NULL;
  361.     }
  362.     if(vis_info)
  363.     {
  364.     FreeVisualInfo(vis_info);
  365.     vis_info = NULL;
  366.     }
  367.     if(new_menu)
  368.     {
  369.     myfree(new_menu);
  370.     new_menu = NULL;
  371.     }
  372. }
  373.